﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotNetNuke.Security.Membership;
using System.Xml.Linq;
using System.Security;
using BrandonHaynes.Membership.Factors;

namespace BrandonHaynes.Membership
	{
	/// <summary>
	/// Class representing a credential for use in authenticating a principal
	/// </summary>
	public class Credential
		{
		public Credential(int portalId)
			{
			status = null;
			PortalId = portalId;
			Values = new Dictionary<string, string>();
			IncompleteFactors = new List<IAuthenticationFactor>();
			}

		public Credential(int portalId, string password)
			: this(portalId)
			{
			this["password"] = password;
			}

		public Credential(int portalId, string password, XElement data)
			: this(portalId, password)
			{
			if(data != null)
				data.Elements().ForEach(node => this[node.Name.ToString()] = (string)node.Value);
			}

		public Credential(int portalId, string password, string xml)
			: this(portalId, password, !string.IsNullOrEmpty(xml) ? XElement.Parse(xml) : null)
			{ }

		/// <summary>
		/// A dictionary mapping credential component names to their values
		/// </summary>
		private Dictionary<string, string> Values { get; set; }
		public int PortalId { get; set; }

		private UserLoginStatus? status;
		/// <summary>
		/// The current status of this credential; defaults to no-permit if no status has been explicitly
		/// specified
		/// </summary>
		public UserLoginStatus Status 
			{
			get { return status != null ? status.Value : UserLoginStatus.LOGIN_FAILURE; }
			set { if(IsValid) status = value; }
			}

		/// <summary>
		/// Gets or sets a component of this credential
		/// </summary>
		/// <param name="name">The name of the component to access</param>
		/// <returns>The value of the credential component</returns>
		public string this[string name]
			{ 
			get 
				{
				string value;
				return Values.TryGetValue(name, out value) ? value : null;
				}
			set
				{ Values[name] = value; }
			}

		/// <summary>
		/// Returns true if this credential does not contain a complete set of information, as indicated by
		/// any factor that it is authenticated against
		/// </summary>
		public bool IsComplete
			{ get { return !IncompleteFactors.Any(); } }

		/// <summary>
		/// A set of factors that have reported that this credential is incomplete for any reason
		/// </summary>
		public IList<IAuthenticationFactor> IncompleteFactors
			{ get; private set; }

		/// <summary>
		/// Indicates whether this credential has been marked valid by all factors that it has been authenticated
		/// against (note that this does not imply that the credential has yet been applied against all relevant 
		/// factors)
		/// </summary>
		public bool IsValid
			{
			get
				{
				return
					status == null ||
					Status == UserLoginStatus.LOGIN_SUCCESS ||
					Status == UserLoginStatus.LOGIN_SUPERUSER ||
					Status == UserLoginStatus.LOGIN_INSECUREADMINPASSWORD ||
					Status == UserLoginStatus.LOGIN_INSECUREHOSTPASSWORD;
				}
			}
		}
	}
